%% return by fail.
%chase(Rules) :- unsetChanged, chaseRules(Rules), changedDuringLastStep, chase(Rules).

%chaseRules([]).
%chaseRules(Rules) :- Rules = [Rule | Tail], chaseOneRule(Rule), chaseRules(Tail).

%% each rule should be a single headed full rule
%chaseOneRule(:-(H,B)) :- call(B), \+ H, genTuples(H),fail.
%chaseOneRule(_).


%%  making use of a rule/2 predicate storing all rules
chase :-
	dynamicalize,
	dyno_egd,
	unset_chase_fail,
	chaseLoop.

chaseLoop :-
	unsetChanged,
	chaseRules,
	chase_egds,
	(changedDuringLastStep -> chaseLoop ; true).

chaseRules :-
	rule(H, B, OH),
	chaseOneRule(H,B,OH),
	fail.
chaseRules.

chaseOneRule(H,B,OH) :-
	call(B),
	\+ OH,
	genTuples(OH),
	fail.
chaseOneRule(_,_,_).

%% declare all predicates appearing in rule/3 to be dynamic
dynamicalize :-
	rule(H,B,_),
	dyno(H),
	dyno(B),
	fail.
dynamicalize .

dyno_egd :-
	egd(B, V1, V2),
	dyno(B),
	fail.
dyno_egd.


%% generate a tuple
genTuples(T) :-
	skolem_term(T, Skolemized),
	addFacts(Skolemized),
	setChanged.

setChanged  :-
	assert(changedDuringLastStep).

unsetChanged :-
	retractall(changedDuringLastStep). %% note we use retractall instead of retract here!



%% make all predicates occuring in the chase rules dynamic
%% must be called before chasing.

% dynamicalize(:-(Head, Body)): dynamicalize a tgd
dynamicalize(:-(H,B)) :-
	dyno(H),
	dyno(B).

%  dyno(CQ): make all predicates appearing
%   in a conjunctive query dynamic, so that
%   we are able to modify the database at runtime.
dyno(','(A,B)) :-
	!,
	dyno(A),
	dyno(B).
dyno(T) :-
    predicate_property(T, built_in),
    !.
dyno(T) :-
	functor(T,F,N),
	dynamic(F/N).


is_built_in(Name/Arity) :-
    functor(T, Name, Arity), predicate_property(T, built_in).

